package main

import (
	"fmt"
	"errors"
	"strconv"
)

// 使用数组来模拟栈的使用
type Stack struct {
	MaxTop int // 栈顶最大值
	Top int // 表示栈顶
	arr [5]int // 数组模拟栈
}

func (this *Stack) Push(val int) (err error) {
	// 先判断栈是否已满
	if this.Top == this.MaxTop - 1 {
		fmt.Println("栈满了")
		return errors.New("stack full")
	}

	this.Top++
	// 放入数据
	this.arr[this.Top] = val
	return

}

// 遍历栈，需要从栈顶开始遍历
func (this *Stack) List() {
	// 先判断栈是否为空
	if this.Top == -1 {
		fmt.Println("stack empty")
		return
	}
	// curTop := this.Top
	fmt.Println("栈的情况如下")
	for i := this.Top; i >= 0; i-- {
		fmt.Printf("arr[%d]=%d\n", i, this.arr[i])
	}
}

// 出栈
func (this *Stack) Pop() (val int, err error) {
	// 判断栈是否为空
	if this.Top == -1 {
		fmt.Println("栈空")
		return 0, errors.New("stack empty")
	}
	// 先取值，再 this.Top--
	val = this.arr[this.Top]
	this.Top--
	return val, nil
}

// 判断一个字符是不是一个运算符
func (this *Stack) IsOper(val int) bool {
	if val == 42 || val == 43 || val == 45 || val == 47 {
		return true
	} else {
		return false
	}
}

// 运算的方法
func (this *Stack) Cal(num1 int, num2 int, oper int) int {
	switch oper {
	case 42:
		return num2 * num1
	case 43:
		return num2 + num1
	case 45:
		return num2 - num1
	case 47:
		return num2 / num1
	default:
		fmt.Println("输入有误")
		return 0
	}
}

// 编写方法返回运算符的优先级
func (this *Stack) Priority(oper int) int {
	if oper == 42 || oper == 47 {
		return 1
	} else if oper == 43 || oper == 45 {
		return 0
	} else {
		fmt.Println("操作符错误")
		return -1
	}
}

func main() {

	// 数栈
	numStack := &Stack {
		MaxTop: 20,
		Top: -1,
	}

	// 符号栈
	operStack := &Stack {
		MaxTop: 20,
		Top: -1,
	}

	exp := "30+2*6-2"
	// 定义index，帮助扫描表达式
	index := 0

	// 为了配合运算，我们定义需要的变量
	num1 := 0
	num2 := 0
	oper := 0
	result := 0
	keepNum := ""

	for {
		ch := exp[index : index + 1]
		temp := int([]byte(ch)[0])
		if operStack.IsOper(temp) { // 说明是符号

			// 如果operStack是一个空栈，直接入栈
			if operStack.Top == -1 {
				operStack.Push(temp)
			} else {
				if operStack.Priority(operStack.arr[operStack.Top]) >= operStack.Priority(temp) {
					num1, _ = numStack.Pop()
					num2, _ = numStack.Pop()
					oper, _ = operStack.Pop()
					result = operStack.Cal(num1, num2, oper)
					numStack.Push(result)
					operStack.Push(temp)
				} else {
					operStack.Push(temp)
				}
			}

		} else { // 说明是数

			// 处理多位数思路
			// 1. 定义一个变量 keepNum string，做拼接
			
			keepNum += ch

			// 2. 每次要向index的前面字符测试一下，看看是不是运算符，再做处理
		
			// 如果已经到表达式最后，那么直接转keepNum
			if index == len(exp) - 1 {
				val, _ := strconv.ParseInt(keepNum, 10, 64)
				numStack.Push(int(val))
			} else {
				// 向index后面测试
				if operStack.IsOper(int([]byte(exp[index+1:index+2])[0])) {
					val, _ := strconv.ParseInt(keepNum, 10, 64)
					numStack.Push(int(val))
					keepNum = ""
				}
			}

			// val, _ := strconv.ParseInt(ch, 10, 64)
			// numStack.Push(int(val))

		}

		// 继续扫描
		if index + 1 == len(exp) {
			break
		}

		index++

	}

	for {
		if operStack.Top == -1 {
			break // 退出条件
		}
		num1, _ = numStack.Pop()
		num2, _ = numStack.Pop()
		oper, _ = operStack.Pop()
		result = operStack.Cal(num1, num2, oper)
		numStack.Push(result)
	}

	res, _ := numStack.Pop()
	fmt.Printf("%s=%v\n", exp, res)

}